﻿using Newtonsoft.Json;
using Onetube.Entities.MostViewedQuery;
using Onetube.Entities.SearchrQuery;
using Onetube.Entities.VideoQuery;
using Onetube.Models.SearchVideo;
using Onetube.Providers.Interfaces;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Onetube.Providers
{
    public class YoutubeVideoProvider : IYoutubeVideoProvider
    {
        private YoutubeVideoProvider videoProvider;
        private YoutubeChannelProvider channelProvider;

        public Task<Entities.VideoQuery.VideoQueryResult> GeVideoInfoAsync(string videoId, string regionCode, CancellationTokenSource cancelTask)
        {
            StringBuilder petitionUri = new StringBuilder("https://www.googleapis.com/youtube/v3/videos?");
         
            petitionUri.AppendFormat("part={0}", "+snippet%2Cstatistics%2CcontentDetails");
            petitionUri.AppendFormat("&id={0}", videoId);
            petitionUri.AppendFormat("&regionCode={0}", regionCode);
          
            petitionUri.AppendFormat("&key={0}", AppKeys.API_KEY);

            var taskCompletitionSource = new TaskCompletionSource<VideoQueryResult>();

            return ResolveRequest(petitionUri, taskCompletitionSource, cancelTask);
        }

        public async Task<Models.SearchVideo.SearchVideoResult> GetMostPopularVideosAsync(string regionCode, string maxResults, CancellationTokenSource cancelTask)
        {
            StringBuilder petitionUri = new StringBuilder("https://www.googleapis.com/youtube/v3/videos?");

            petitionUri.AppendFormat("part={0}", "+snippet%2Cstatistics%2CcontentDetails");
            petitionUri.AppendFormat("&chart={0}", "mostPopular");
            petitionUri.AppendFormat("&regionCode={0}", regionCode);
            petitionUri.AppendFormat("&maxResults={0}", maxResults);
            petitionUri.AppendFormat("&key={0}", AppKeys.API_KEY);

            var taskCompletitionSource = new TaskCompletionSource<VideoQueryResult>();
            var videoResult = new Models.SearchVideo.SearchVideoResult();
            var result = await ResolveRequest(petitionUri, taskCompletitionSource, cancelTask).ConfigureAwait(false);

            if (result != null)
            {
                videoResult.etag = result.Etag;
                videoResult.kind = result.Kind;
                videoResult.nextPageToken = result.NextPageToken;
                videoResult.prevPageToken = result.prevPageToken;
                videoResult.pageInfo = new Models.SearchVideo.PageInfo { resultsPerPage = result.PageInfo.ResultsPerPage, totalResults = result.PageInfo.TotalResults };
                videoResult.prevPageToken = result.prevPageToken;
                videoResult.items = new List<Models.SearchVideo.Item>();
                if (result.Items != null)
                {
                    if (result.Items.Any())
                    {
                        var channelProvider = new YoutubeChannelProvider();
                        string channelIds = string.Empty;
                        int count = 0;
                        for (int i = 0; i <= result.Items.Count() - 1; i++)
                        {
                            count++;
                            var item = result.Items.ElementAt(i);
                            if (item.Id != null)
                            {
                                if (count >= result.Items.Count())
                                {
                                    channelIds += item.Snippet.ChannelId;
                                }
                                else
                                {
                                    channelIds += item.Snippet.ChannelId + ",";
                                }
                            }
                        }

                        var channelDataList = await channelProvider.SearchChannelByIdAsync(channelIds, cancelTask).ConfigureAwait(false);
                        foreach (var videoItem in result.Items)
                        {
                            var dataItem = new Onetube.Models.SearchVideo.Item();
                            dataItem.etag = videoItem.Etag;
                            dataItem.id = new Onetube.Models.SearchVideo.Id { videoId = videoItem.Id, kind = string.Empty };
                            dataItem.kind = videoItem.Kind;
                            var snippet = new Onetube.Models.SearchVideo.Snippet();
                            snippet.channelId = videoItem.Snippet.ChannelId;
                            snippet.channelTitle = videoItem.Snippet.ChannelTitle;
                            snippet.description = videoItem.Snippet.Description;
                            snippet.liveBroadcastContent = videoItem.Snippet.LiveBroadcastContent;
                            snippet.publishedAt = videoItem.Snippet.PublishedAt;
                            snippet.title = videoItem.Snippet.Title;
                            snippet.thumbnails = new Onetube.Models.SearchVideo.Thumbnails
                            {
                                @default = new Onetube.Models.SearchVideo.Default { url = videoItem.Snippet.Thumbnails.@Default.Url },
                                high = new Onetube.Models.SearchVideo.High { url = videoItem.Snippet.Thumbnails.High.Url },
                                medium = new Onetube.Models.SearchVideo.Medium { url = videoItem.Snippet.Thumbnails.Medium.Url }
                            };
                            var contentDetails = new Onetube.Models.SearchVideo.ContentDetails();

                            contentDetails.caption = videoItem.ContentDetails.Caption;
                            contentDetails.definition = videoItem.ContentDetails.Definition;
                            contentDetails.dimension = videoItem.ContentDetails.Dimension;
                            contentDetails.duration = videoItem.ContentDetails.Duration;
                            contentDetails.licensedContent = videoItem.ContentDetails.LicensedContent;

                            snippet.contentDetails = contentDetails;

                            var statistics = new Onetube.Models.SearchVideo.Statistics();
                            statistics.commentCount = videoItem.Statistics.CommentCount;
                            statistics.dislikeCount = videoItem.Statistics.DislikeCount;
                            statistics.favoriteCount = videoItem.Statistics.FavoriteCount;
                            statistics.likeCount = videoItem.Statistics.LikeCount;
                            statistics.viewCount = videoItem.Statistics.ViewCount;

                            snippet.statistics = statistics;
                            dataItem.snippet = snippet;

                            if (channelDataList != null)
                            {
                                if (channelDataList.Items != null)
                                    if (channelDataList.Items.Any())
                                    {
                                        var correspondChannel = channelDataList.Items.FirstOrDefault(x => x.Id.Equals(videoItem.Snippet.ChannelId));
                                        if (correspondChannel != null)
                                        {
                                            dataItem.snippet.channelDetails = new ChannelSnippet();
                                            dataItem.snippet.channelDetails.Description = correspondChannel.Snippet.Description;
                                            dataItem.snippet.channelDetails.PublishedAt = correspondChannel.Snippet.PublishedAt;
                                            dataItem.snippet.channelDetails.Thumbnails = new Models.SearchVideo.Thumbnails
                                            {
                                                @default = new Models.SearchVideo.Default
                                                {
                                                    url = correspondChannel.Snippet.Thumbnails.Default.Url
                                                },
                                                high = new Models.SearchVideo.High
                                                {
                                                    url = correspondChannel.Snippet.Thumbnails.High.Url
                                                },
                                                medium = new Models.SearchVideo.Medium
                                                {
                                                    url = correspondChannel.Snippet.Thumbnails.Medium.Url
                                                }
                                            };
                                            dataItem.snippet.channelDetails.Title = correspondChannel.Snippet.Title;
                                        }
                                    }
                            }

                            videoResult.items.Add(dataItem);
                        }
                        channelDataList = null;
                       
                        channelIds = null;
                    }
                }
                result = null;
            }
            return videoResult;
        }

        public async Task<SearchVideoResult> GetMostViewedVideosAsync(string regionCode, string maxResults, CancellationTokenSource cancelTask)
        {
            StringBuilder petitionUri = new StringBuilder("https://gdata.youtube.com/feeds/api/standardfeeds/");

            petitionUri.Append(regionCode);
            petitionUri.AppendFormat("/most_viewed?{0}", "v=2");
            petitionUri.AppendFormat("&max-results={0}", maxResults);
           
            petitionUri.AppendFormat("&alt={0}", "json");

            petitionUri.AppendFormat("&key={0}", AppKeys.API_KEY);

            var taskCompletitionSource = new TaskCompletionSource<Entities.MostViewedQuery.MostViewedQueryResult>();
            var videoResult = new Models.SearchVideo.SearchVideoResult();
            videoResult.items = new List<Models.SearchVideo.Item>();
            var result = await ResolveMostReviewedRequest(petitionUri, taskCompletitionSource, cancelTask).ConfigureAwait(false);

            if (result != null)
            {
                if (result.Feed != null)
                {
                    if (result.Feed.Entry != null) 
                    {
                        channelProvider = new YoutubeChannelProvider();
                        foreach (var entry in result.Feed.Entry)
                        {
                            var item = new Models.SearchVideo.Item();
                            item.id = new Onetube.Models.SearchVideo.Id { videoId = getFormattedVideoId(entry.Id.T) };
                            var snippet = new Models.SearchVideo.Snippet();
                            snippet.title = entry.Title.T;
                            snippet.thumbnails = new Models.SearchVideo.Thumbnails();
                            if (entry.MediaGroup.MediaThumbnail != null)
                            {
                                var thumb1 = entry.MediaGroup.MediaThumbnail.FirstOrDefault().Url;
                                var thumb2 = entry.MediaGroup.MediaThumbnail.ElementAt(1).Url;
                                var thumb3 = entry.MediaGroup.MediaThumbnail.ElementAt(2).Url;
                                snippet.thumbnails = new Models.SearchVideo.Thumbnails()
                                {
                                    @default = new Models.SearchVideo.Default
                                    {
                                        url = thumb1
                                    },
                                    high = new Models.SearchVideo.High
                                    {
                                        url = thumb3
                                    },
                                    medium = new Models.SearchVideo.Medium
                                    {
                                        url = thumb2
                                    }
                                };
                            }
                            
                            snippet.contentDetails = new Models.SearchVideo.ContentDetails();
                            snippet.contentDetails.duration = entry.MediaGroup.YtDuration.Seconds;
                            snippet.statistics = new Models.SearchVideo.Statistics();
                            if (entry.YtStatistics != null)
                            {
                                snippet.statistics.viewCount = entry.YtStatistics.ViewCount;
                                snippet.statistics.favoriteCount = entry.YtStatistics.FavoriteCount;
                            }
                            else
                            {
                                snippet.statistics.viewCount = "0";
                                snippet.statistics.favoriteCount = "0";
                            }

                            if (entry.YtRating != null)
                            {
                                snippet.statistics.likeCount = entry.YtRating.NumLikes;
                                snippet.statistics.dislikeCount = entry.YtRating.NumDislikes;
                            }
                            else
                            {
                                snippet.statistics.likeCount = "0";
                                snippet.statistics.dislikeCount = "0";
                            }

                            if (entry.MediaGroup.YtUploaderId != null)
                            {
                                var channelInfo = await channelProvider.SearchChannelByIdAsync(entry.MediaGroup.YtUploaderId.T, cancelTask).ConfigureAwait(false);
                                if (channelInfo != null && channelInfo.Items!=null)
                                {
                                    snippet.channelDetails = new ChannelSnippet();
                                    snippet.channelDetails.Description = entry.MediaGroup.MediaDescription.T;
                                   
                                    snippet.channelDetails.Thumbnails = new Models.SearchVideo.Thumbnails();
                                    snippet.channelDetails.Thumbnails.@default = new Models.SearchVideo.Default { url = channelInfo.Items.First().Snippet.Thumbnails.Default.Url };
                                    snippet.channelDetails.Title = channelInfo.Items.First().Snippet.Title;
                                    snippet.publishedAt = entry.Published.T; 
                                    
                                    channelInfo = null;
                                  
                                }
                                item.snippet = snippet;
                                videoResult.items.Add(item);
                            }
                        }
                    }
                }
            }
            result = null;
            
            channelProvider = null;
            return videoResult;
        }

        public async Task<SearchVideoResult> GetVideosByCategoryAsync(string regionCode, string categoryId, string maxResults, CancellationTokenSource cancelTask)
        {
            StringBuilder petitionUri = new StringBuilder("https://www.googleapis.com/youtube/v3/videos?");

            petitionUri.AppendFormat("part={0}", "+snippet%2Cstatistics%2CcontentDetails");
            petitionUri.AppendFormat("&chart={0}", "mostPopular");
            petitionUri.AppendFormat("&maxResults={0}", maxResults);
            petitionUri.AppendFormat("&regionCode={0}", regionCode);
            petitionUri.AppendFormat("&videoCategoryId={0}", categoryId);
            petitionUri.AppendFormat("&key={0}", AppKeys.API_KEY);
            
            var taskCompletitionSource = new TaskCompletionSource<Entities.VideoQuery.VideoQueryResult>();
            var videoResult = new Models.SearchVideo.SearchVideoResult();
            videoResult.items = new List<Models.SearchVideo.Item>();
            var result = await ResolveRequest(petitionUri, taskCompletitionSource, cancelTask).ConfigureAwait(false);

            if (result != null)
            {
                videoResult.etag = result.Etag;
                videoResult.kind = result.Kind;
                videoResult.nextPageToken = result.NextPageToken;
                videoResult.prevPageToken = result.prevPageToken;
                videoResult.pageInfo = new Models.SearchVideo.PageInfo { resultsPerPage = result.PageInfo.ResultsPerPage, totalResults = result.PageInfo.TotalResults };
                videoResult.prevPageToken = result.prevPageToken;
                videoResult.items = new List<Models.SearchVideo.Item>();
                if (result.Items != null)
                {
                    if (result.Items.Any())
                    {
                        var channelProvider = new YoutubeChannelProvider();
                        string channelIds = string.Empty;
                        int count = 0;
                        for (int i = 0; i <= result.Items.Count() - 1; i++)
                        {
                            count++;
                            var item = result.Items.ElementAt(i);
                            if (item.Id != null)
                            {
                                if (count >= result.Items.Count())
                                {
                                    channelIds += item.Snippet.ChannelId;
                                }
                                else
                                {
                                    channelIds += item.Snippet.ChannelId + ",";
                                }
                            }
                        }

                        var channelDataList = await channelProvider.SearchChannelByIdAsync(channelIds, cancelTask).ConfigureAwait(false);
                        foreach (var videoItem in result.Items)
                        {
                            var dataItem = new Onetube.Models.SearchVideo.Item();
                            dataItem.etag = videoItem.Etag;
                            dataItem.id = new Onetube.Models.SearchVideo.Id { videoId = videoItem.Id, kind = string.Empty };
                            dataItem.kind = videoItem.Kind;
                            var snippet = new Onetube.Models.SearchVideo.Snippet();
                            snippet.channelId = videoItem.Snippet.ChannelId;
                            snippet.channelTitle = videoItem.Snippet.ChannelTitle;
                            snippet.description = videoItem.Snippet.Description;
                            snippet.liveBroadcastContent = videoItem.Snippet.LiveBroadcastContent;
                            snippet.publishedAt = videoItem.Snippet.PublishedAt;
                            snippet.title = videoItem.Snippet.Title;
                            snippet.thumbnails = new Onetube.Models.SearchVideo.Thumbnails
                            {
                                @default = new Onetube.Models.SearchVideo.Default { url = videoItem.Snippet.Thumbnails.@Default.Url },
                                high = new Onetube.Models.SearchVideo.High { url = videoItem.Snippet.Thumbnails.High.Url },
                                medium = new Onetube.Models.SearchVideo.Medium { url = videoItem.Snippet.Thumbnails.Medium.Url }
                            };
                            var contentDetails = new Onetube.Models.SearchVideo.ContentDetails();

                            contentDetails.caption = videoItem.ContentDetails.Caption;
                            contentDetails.definition = videoItem.ContentDetails.Definition;
                            contentDetails.dimension = videoItem.ContentDetails.Dimension;
                            contentDetails.duration = videoItem.ContentDetails.Duration;
                            contentDetails.licensedContent = videoItem.ContentDetails.LicensedContent;

                            snippet.contentDetails = contentDetails;

                            var statistics = new Onetube.Models.SearchVideo.Statistics();
                            statistics.commentCount = videoItem.Statistics.CommentCount;
                            statistics.dislikeCount = videoItem.Statistics.DislikeCount;
                            statistics.favoriteCount = videoItem.Statistics.FavoriteCount;
                            statistics.likeCount = videoItem.Statistics.LikeCount;
                            statistics.viewCount = videoItem.Statistics.ViewCount;

                            snippet.statistics = statistics;
                            dataItem.snippet = snippet;

                            if (channelDataList != null)
                            {
                                if (channelDataList.Items.Any())
                                {
                                    var correspondChannel = channelDataList.Items.FirstOrDefault(x => x.Id.Equals(videoItem.Snippet.ChannelId));
                                    if (correspondChannel != null)
                                    {
                                        dataItem.snippet.channelDetails = new ChannelSnippet();
                                        dataItem.snippet.channelDetails.Description = correspondChannel.Snippet.Description;
                                        dataItem.snippet.channelDetails.PublishedAt = correspondChannel.Snippet.PublishedAt;
                                        dataItem.snippet.channelDetails.Thumbnails = new Models.SearchVideo.Thumbnails
                                        {
                                            @default = new Models.SearchVideo.Default
                                            {
                                                url = correspondChannel.Snippet.Thumbnails.Default.Url
                                            },
                                            high = new Models.SearchVideo.High
                                            {
                                                url = correspondChannel.Snippet.Thumbnails.High.Url
                                            },
                                            medium = new Models.SearchVideo.Medium
                                            {
                                                url = correspondChannel.Snippet.Thumbnails.Medium.Url
                                            }
                                        };
                                        dataItem.snippet.channelDetails.Title = correspondChannel.Snippet.Title;
                                    }
                                }
                            }

                            videoResult.items.Add(dataItem);
                        }
                        channelDataList = null;
                    }
                }
                result = null;
            }

            return videoResult;
        }

        public async Task<SearchVideoResult> GetVideosByCategoryPrevAsync(string prevPageToken, string regionCode, string categoryId, string maxResults, CancellationTokenSource cancelTask)
        {
            return null;
        }

        public async Task<SearchVideoResult> GetVideosByCategoryNextAsync(string nextPageToken, string regionCode, string categoryId, string maxResults, CancellationTokenSource cancelTask)
        {
            StringBuilder petitionUri = new StringBuilder("https://www.googleapis.com/youtube/v3/videos?");

            petitionUri.AppendFormat("part={0}", "+snippet%2Cstatistics%2CcontentDetails");
            petitionUri.AppendFormat("&chart={0}", "mostPopular");
            petitionUri.AppendFormat("&maxResults={0}", maxResults);
            petitionUri.AppendFormat("&regionCode={0}", regionCode);
            petitionUri.AppendFormat("&pageToken={0}", nextPageToken);
            petitionUri.AppendFormat("&videoCategoryId={0}", categoryId);
            petitionUri.AppendFormat("&key={0}", AppKeys.API_KEY);

            var taskCompletitionSource = new TaskCompletionSource<Entities.VideoQuery.VideoQueryResult>();
            var videoResult = new Models.SearchVideo.SearchVideoResult();
            videoResult.items = new List<Models.SearchVideo.Item>();
            var result = await ResolveRequest(petitionUri, taskCompletitionSource, cancelTask).ConfigureAwait(false);

            if (result != null)
            {
                videoResult.etag = result.Etag;
                videoResult.kind = result.Kind;
                videoResult.nextPageToken = result.NextPageToken;
                videoResult.prevPageToken = result.prevPageToken;
                videoResult.pageInfo = new Models.SearchVideo.PageInfo { resultsPerPage = result.PageInfo.ResultsPerPage, totalResults = result.PageInfo.TotalResults };
                videoResult.prevPageToken = result.prevPageToken;
                videoResult.items = new List<Models.SearchVideo.Item>();
                if (result.Items != null)
                {
                    if (result.Items.Any())
                    {
                        var channelProvider = new YoutubeChannelProvider();
                        string channelIds = string.Empty;
                        int count = 0;
                        for (int i = 0; i <= result.Items.Count() - 1; i++)
                        {
                            count++;
                            var item = result.Items.ElementAt(i);
                            if (item.Id != null)
                            {
                                if (count >= result.Items.Count())
                                {
                                    channelIds += item.Snippet.ChannelId;
                                }
                                else
                                {
                                    channelIds += item.Snippet.ChannelId + ",";
                                }
                            }
                        }

                        var channelDataList = await channelProvider.SearchChannelByIdAsync(channelIds, cancelTask).ConfigureAwait(false);
                        foreach (var videoItem in result.Items)
                        {
                            var dataItem = new Onetube.Models.SearchVideo.Item();
                            dataItem.etag = videoItem.Etag;
                            dataItem.id = new Onetube.Models.SearchVideo.Id { videoId = videoItem.Id, kind = string.Empty };
                            dataItem.kind = videoItem.Kind;
                            var snippet = new Onetube.Models.SearchVideo.Snippet();
                            snippet.channelId = videoItem.Snippet.ChannelId;
                            snippet.channelTitle = videoItem.Snippet.ChannelTitle;
                            snippet.description = videoItem.Snippet.Description;
                            snippet.liveBroadcastContent = videoItem.Snippet.LiveBroadcastContent;
                            snippet.publishedAt = videoItem.Snippet.PublishedAt;
                            snippet.title = videoItem.Snippet.Title;
                            snippet.thumbnails = new Onetube.Models.SearchVideo.Thumbnails
                            {
                                @default = new Onetube.Models.SearchVideo.Default { url = videoItem.Snippet.Thumbnails.@Default.Url },
                                high = new Onetube.Models.SearchVideo.High { url = videoItem.Snippet.Thumbnails.High.Url },
                                medium = new Onetube.Models.SearchVideo.Medium { url = videoItem.Snippet.Thumbnails.Medium.Url }
                            };
                            var contentDetails = new Onetube.Models.SearchVideo.ContentDetails();

                            contentDetails.caption = videoItem.ContentDetails.Caption;
                            contentDetails.definition = videoItem.ContentDetails.Definition;
                            contentDetails.dimension = videoItem.ContentDetails.Dimension;
                            contentDetails.duration = videoItem.ContentDetails.Duration;
                            contentDetails.licensedContent = videoItem.ContentDetails.LicensedContent;

                            snippet.contentDetails = contentDetails;

                            var statistics = new Onetube.Models.SearchVideo.Statistics();
                            statistics.commentCount = videoItem.Statistics.CommentCount;
                            statistics.dislikeCount = videoItem.Statistics.DislikeCount;
                            statistics.favoriteCount = videoItem.Statistics.FavoriteCount;
                            statistics.likeCount = videoItem.Statistics.LikeCount;
                            statistics.viewCount = videoItem.Statistics.ViewCount;

                            snippet.statistics = statistics;
                            dataItem.snippet = snippet;

                            if (channelDataList != null)
                            {
                                if (channelDataList.Items.Any())
                                {
                                    var correspondChannel = channelDataList.Items.FirstOrDefault(x => x.Id.Equals(videoItem.Snippet.ChannelId));
                                    if (correspondChannel != null)
                                    {
                                        dataItem.snippet.channelDetails = new ChannelSnippet();
                                        dataItem.snippet.channelDetails.Description = correspondChannel.Snippet.Description;
                                        dataItem.snippet.channelDetails.PublishedAt = correspondChannel.Snippet.PublishedAt;
                                        dataItem.snippet.channelDetails.Thumbnails = new Models.SearchVideo.Thumbnails
                                        {
                                            @default = new Models.SearchVideo.Default
                                            {
                                                url = correspondChannel.Snippet.Thumbnails.Default.Url
                                            },
                                            high = new Models.SearchVideo.High
                                            {
                                                url = correspondChannel.Snippet.Thumbnails.High.Url
                                            },
                                            medium = new Models.SearchVideo.Medium
                                            {
                                                url = correspondChannel.Snippet.Thumbnails.Medium.Url
                                            }
                                        };
                                        dataItem.snippet.channelDetails.Title = correspondChannel.Snippet.Title;
                                    }
                                }
                            }

                            videoResult.items.Add(dataItem);
                        }
                         
                        channelIds = null;
                        channelDataList = null;
                    }
                }
                result = null;
            }

            return videoResult;
        }

        public async Task<SearchVideoResult> GetVideosByChannelIdAsync(string channelId, string regionCode, string categoryId, string maxResults, Entities.Enums.SearchOrder order, CancellationTokenSource cancelTask)
        {
            StringBuilder petitionUri = new StringBuilder("https://www.googleapis.com/youtube/v3/search?");

            petitionUri.AppendFormat("part={0}", "snippet");
            petitionUri.AppendFormat("&channelId={0}", channelId);
            petitionUri.AppendFormat("&maxResults={0}", maxResults);
            petitionUri.AppendFormat("&order={0}", Helpers.SearchHelpers.ParseSearchOrderEnum(order));
            petitionUri.AppendFormat("&regionCode={0}", regionCode);
            petitionUri.AppendFormat("&type={0}", "video");
            petitionUri.AppendFormat("&key={0}", AppKeys.API_KEY);
            var taskCompletitionSource = new TaskCompletionSource<SearchQueryResult>();
            var videoResult = new Models.SearchVideo.SearchVideoResult();
            var result = await ResolveRequest(petitionUri, taskCompletitionSource, cancelTask).ConfigureAwait(false);

            if (result != null)
            {
                videoResult.etag = result.etag;
                videoResult.kind = result.kind;
                videoResult.nextPageToken = result.nextPageToken;
                videoResult.pageInfo = new Models.SearchVideo.PageInfo { resultsPerPage = result.pageInfo.resultsPerPage, totalResults = result.pageInfo.totalResults };
                videoResult.prevPageToken = result.prevPageToken;
                videoResult.items = new List<Models.SearchVideo.Item>();
                if (result.items != null)
                {
                    if (result.items.Any())
                    {
                        channelProvider = new YoutubeChannelProvider();
                        string videoIds = string.Empty;
                        string channelIds = string.Empty;
                        int count = 0;
                        for (int i = 0; i <= result.items.Count - 1; i++)
                        {
                            count++;
                            var item = result.items.ElementAt(i);
                            if (item.id != null)
                            {
                                if (count >= result.items.Count)
                                {
                                    videoIds += item.id.videoId;
                                    channelIds += item.snippet.channelId;
                                }
                                else
                                {
                                    videoIds += item.id.videoId + ",";
                                    channelIds += item.snippet.channelId + ",";
                                }
                            }
                        }

                        var videoDataList = await GeVideoInfoAsync(videoIds, "MX", cancelTask).ConfigureAwait(false);
                        var channelDataList = await channelProvider.SearchChannelByIdAsync(channelIds, cancelTask);
                        if (videoDataList != null)
                        {
                            foreach (var videoItem in result.items)
                            {
                                var dataItem = new Onetube.Models.SearchVideo.Item();

                                dataItem.etag = videoResult.etag;
                                dataItem.id = new Onetube.Models.SearchVideo.Id { kind = videoItem.id.kind, videoId = videoItem.id.videoId };
                                dataItem.kind = videoItem.kind;
                                var snippet = new Onetube.Models.SearchVideo.Snippet();
                                snippet.channelId = videoItem.snippet.channelId;
                                snippet.channelTitle = videoItem.snippet.channelTitle;
                                snippet.description = videoItem.snippet.description;
                                snippet.liveBroadcastContent = videoItem.snippet.liveBroadcastContent;
                                snippet.publishedAt = videoItem.snippet.publishedAt;
                                snippet.title = videoItem.snippet.title;
                                snippet.thumbnails = new Onetube.Models.SearchVideo.Thumbnails
                                {
                                    @default = new Onetube.Models.SearchVideo.Default { url = videoItem.snippet.thumbnails.@default.url },
                                    high = new Onetube.Models.SearchVideo.High { url = videoItem.snippet.thumbnails.high.url },
                                    medium = new Onetube.Models.SearchVideo.Medium { url = videoItem.snippet.thumbnails.medium.url }
                                };
                                var contentDetails = new Onetube.Models.SearchVideo.ContentDetails();
                                var correspondVideo = videoDataList.Items.FirstOrDefault(x => x.Id.Equals(videoItem.id.videoId));
                                if (correspondVideo != null)
                                {
                                    contentDetails.caption = correspondVideo.ContentDetails.Caption;
                                    contentDetails.definition = correspondVideo.ContentDetails.Definition;
                                    contentDetails.dimension = correspondVideo.ContentDetails.Dimension;
                                    contentDetails.duration = correspondVideo.ContentDetails.Duration;
                                    contentDetails.licensedContent = correspondVideo.ContentDetails.LicensedContent;
                                }

                                snippet.contentDetails = contentDetails;

                                var statistics = new Onetube.Models.SearchVideo.Statistics();
                                statistics.commentCount = correspondVideo.Statistics.CommentCount;
                                statistics.dislikeCount = correspondVideo.Statistics.DislikeCount;
                                statistics.favoriteCount = correspondVideo.Statistics.FavoriteCount;
                                statistics.likeCount = correspondVideo.Statistics.LikeCount;
                                statistics.viewCount = correspondVideo.Statistics.ViewCount;

                                snippet.statistics = statistics;
                                dataItem.snippet = snippet;
                                if (channelDataList != null)
                                {
                                    if (channelDataList.Items!=null && channelDataList.Items.Any())
                                    {
                                        var correspondChannel = channelDataList.Items.FirstOrDefault(x => x.Id.Equals(videoItem.snippet.channelId));
                                        if (correspondChannel != null)
                                        {
                                            dataItem.snippet.channelDetails = new ChannelSnippet();
                                            dataItem.snippet.channelDetails.Description = correspondChannel.Snippet.Description;
                                            dataItem.snippet.channelDetails.PublishedAt = correspondChannel.Snippet.PublishedAt;
                                            dataItem.snippet.channelDetails.Thumbnails = new Models.SearchVideo.Thumbnails
                                            {
                                                @default = new Models.SearchVideo.Default
                                                {
                                                    url = correspondChannel.Snippet.Thumbnails.Default.Url
                                                },
                                                high = new Models.SearchVideo.High
                                                {
                                                    url = correspondChannel.Snippet.Thumbnails.High.Url
                                                },
                                                medium = new Models.SearchVideo.Medium
                                                {
                                                    url = correspondChannel.Snippet.Thumbnails.Medium.Url
                                                }
                                            };
                                            dataItem.snippet.channelDetails.Title = correspondChannel.Snippet.Title;
                                        }
                                    }
                                }
                                videoResult.items.Add(dataItem);
                            }
                        }
                        videoDataList = null;
                        channelDataList = null;
                        videoIds = null;
                        channelIds = null;
                    }
                }
                result = null;
            }

            return videoResult;
        }

        public Task<SearchVideoResult> GetVideosByChannelIdAsyncPrevAsync(string prevPageToken, string channelId, string regionCode, string categoryId, string maxResults, Entities.Enums.SearchOrder order, CancellationTokenSource cancelTask)
        {
            return null;
        }

        public async Task<SearchVideoResult> GetVideosByChannelIdAsyncNextAsync(string nextPageToken, string channelId, string regionCode, string categoryId, string maxResults, Entities.Enums.SearchOrder order, CancellationTokenSource cancelTask)
        {
            StringBuilder petitionUri = new StringBuilder("https://www.googleapis.com/youtube/v3/search?");

            petitionUri.AppendFormat("part={0}", "snippet");
            petitionUri.AppendFormat("&channelId={0}", channelId);
            petitionUri.AppendFormat("&maxResults={0}", maxResults);
            petitionUri.AppendFormat("&order={0}", Helpers.SearchHelpers.ParseSearchOrderEnum(order));
            petitionUri.AppendFormat("&regionCode={0}", regionCode);
            petitionUri.AppendFormat("&pageToken={0}", nextPageToken);
            petitionUri.AppendFormat("&type={0}", "video");
            petitionUri.AppendFormat("&key={0}", AppKeys.API_KEY);
            var taskCompletitionSource = new TaskCompletionSource<SearchQueryResult>();
            var videoResult = new Models.SearchVideo.SearchVideoResult();
            var result = await ResolveRequest(petitionUri, taskCompletitionSource, cancelTask).ConfigureAwait(false);

            if (result != null)
            {
                videoResult.etag = result.etag;
                videoResult.kind = result.kind;
                videoResult.nextPageToken = result.nextPageToken;
                videoResult.pageInfo = new Models.SearchVideo.PageInfo { resultsPerPage = result.pageInfo.resultsPerPage, totalResults = result.pageInfo.totalResults };
                videoResult.prevPageToken = result.prevPageToken;
                videoResult.items = new List<Models.SearchVideo.Item>();
                if (result.items != null)
                {
                    if (result.items.Any())
                    {
                        channelProvider = new YoutubeChannelProvider();
                        string videoIds = string.Empty;
                        string channelIds = string.Empty;
                        int count = 0;
                        for (int i = 0; i <= result.items.Count - 1; i++)
                        {
                            count++;
                            var item = result.items.ElementAt(i);
                            if (item.id != null)
                            {
                                if (count >= result.items.Count)
                                {
                                    videoIds += item.id.videoId;
                                    channelIds += item.snippet.channelId;
                                }
                                else
                                {
                                    videoIds += item.id.videoId + ",";
                                    channelIds += item.snippet.channelId + ",";
                                }
                            }
                        }

                        var videoDataList = await GeVideoInfoAsync(videoIds, "MX", cancelTask).ConfigureAwait(false);
                        var channelDataList = await channelProvider.SearchChannelByIdAsync(channelIds, cancelTask).ConfigureAwait(false);
                        if (videoDataList != null)
                        {
                            foreach (var videoItem in result.items)
                            {
                                var dataItem = new Onetube.Models.SearchVideo.Item();

                                dataItem.etag = videoResult.etag;
                                dataItem.id = new Onetube.Models.SearchVideo.Id { kind = videoItem.id.kind, videoId = videoItem.id.videoId };
                                dataItem.kind = videoItem.kind;
                                var snippet = new Onetube.Models.SearchVideo.Snippet();
                                snippet.channelId = videoItem.snippet.channelId;
                                snippet.channelTitle = videoItem.snippet.channelTitle;
                                snippet.description = videoItem.snippet.description;
                                snippet.liveBroadcastContent = videoItem.snippet.liveBroadcastContent;
                                snippet.publishedAt = videoItem.snippet.publishedAt;
                                snippet.title = videoItem.snippet.title;
                                snippet.thumbnails = new Onetube.Models.SearchVideo.Thumbnails
                                {
                                    @default = new Onetube.Models.SearchVideo.Default { url = videoItem.snippet.thumbnails.@default.url },
                                    high = new Onetube.Models.SearchVideo.High { url = videoItem.snippet.thumbnails.high.url },
                                    medium = new Onetube.Models.SearchVideo.Medium { url = videoItem.snippet.thumbnails.medium.url }
                                };
                                var contentDetails = new Onetube.Models.SearchVideo.ContentDetails();
                                var correspondVideo = videoDataList.Items.FirstOrDefault(x => x.Id.Equals(videoItem.id.videoId));
                                if (correspondVideo != null)
                                {
                                    contentDetails.caption = correspondVideo.ContentDetails.Caption;
                                    contentDetails.definition = correspondVideo.ContentDetails.Definition;
                                    contentDetails.dimension = correspondVideo.ContentDetails.Dimension;
                                    contentDetails.duration = correspondVideo.ContentDetails.Duration;
                                    contentDetails.licensedContent = correspondVideo.ContentDetails.LicensedContent;
                                }

                                snippet.contentDetails = contentDetails;

                                var statistics = new Onetube.Models.SearchVideo.Statistics();
                                statistics.commentCount = correspondVideo.Statistics.CommentCount;
                                statistics.dislikeCount = correspondVideo.Statistics.DislikeCount;
                                statistics.favoriteCount = correspondVideo.Statistics.FavoriteCount;
                                statistics.likeCount = correspondVideo.Statistics.LikeCount;
                                statistics.viewCount = correspondVideo.Statistics.ViewCount;

                                snippet.statistics = statistics;
                                dataItem.snippet = snippet;
                                if (channelDataList != null)
                                {
                                    if (channelDataList.Items.Any())
                                    {
                                        var correspondChannel = channelDataList.Items.FirstOrDefault(x => x.Id.Equals(videoItem.snippet.channelId));
                                        if (correspondChannel != null)
                                        {
                                            dataItem.snippet.channelDetails = new ChannelSnippet();
                                            dataItem.snippet.channelDetails.Description = correspondChannel.Snippet.Description;
                                            dataItem.snippet.channelDetails.PublishedAt = correspondChannel.Snippet.PublishedAt;
                                            dataItem.snippet.channelDetails.Thumbnails = new Models.SearchVideo.Thumbnails
                                            {
                                                @default = new Models.SearchVideo.Default
                                                {
                                                    url = correspondChannel.Snippet.Thumbnails.Default.Url
                                                },
                                                high = new Models.SearchVideo.High
                                                {
                                                    url = correspondChannel.Snippet.Thumbnails.High.Url
                                                },
                                                medium = new Models.SearchVideo.Medium
                                                {
                                                    url = correspondChannel.Snippet.Thumbnails.Medium.Url
                                                }
                                            };
                                            dataItem.snippet.channelDetails.Title = correspondChannel.Snippet.Title;
                                        }
                                    }
                                }
                                videoResult.items.Add(dataItem);
                            }
                        }
                        videoDataList = null;
                        channelDataList = null;
                        videoIds = null;
                        channelIds = null;
                    }
                }
                result = null;
            }

            return videoResult;
        }

        public Task<SearchVideoResult> GetMostPopularVideosPrevAsync(string prevPageToken, string regionCode, string maxResults, CancellationTokenSource cancelTask)
        {
            return null;
        }

        public async Task<SearchVideoResult> GetMostPopularVideosNextAsync(string nextPageToken, string regionCode, string maxResults, CancellationTokenSource cancelTask)
        {
            StringBuilder petitionUri = new StringBuilder("https://www.googleapis.com/youtube/v3/videos?");

            petitionUri.AppendFormat("part={0}", "+snippet%2Cstatistics%2CcontentDetails");
            petitionUri.AppendFormat("&chart={0}", "mostPopular");
            petitionUri.AppendFormat("&regionCode={0}", regionCode);
            petitionUri.AppendFormat("&pageToken={0}", nextPageToken);
            petitionUri.AppendFormat("&maxResults={0}", maxResults);
            petitionUri.AppendFormat("&key={0}", AppKeys.API_KEY);

            var taskCompletitionSource = new TaskCompletionSource<VideoQueryResult>();
            var videoResult = new Models.SearchVideo.SearchVideoResult();
            var result = await ResolveRequest(petitionUri, taskCompletitionSource, cancelTask).ConfigureAwait(false);

            if (result != null)
            {
                videoResult.etag = result.Etag;
                videoResult.kind = result.Kind;
                videoResult.nextPageToken = result.NextPageToken;
                videoResult.prevPageToken = result.prevPageToken;
                videoResult.pageInfo = new Models.SearchVideo.PageInfo { resultsPerPage = result.PageInfo.ResultsPerPage, totalResults = result.PageInfo.TotalResults };
                videoResult.prevPageToken = result.prevPageToken;
                videoResult.items = new List<Models.SearchVideo.Item>();
                if (result.Items != null)
                {
                    if (result.Items.Any())
                    {
                        var channelProvider = new YoutubeChannelProvider();
                        string channelIds = string.Empty;
                        int count = 0;
                        for (int i = 0; i <= result.Items.Count() - 1; i++)
                        {
                            count++;
                            var item = result.Items.ElementAt(i);
                            if (item.Id != null)
                            {
                                if (count >= result.Items.Count())
                                {
                                    channelIds += item.Snippet.ChannelId;
                                }
                                else
                                {
                                    channelIds += item.Snippet.ChannelId + ",";
                                }
                            }
                        }

                        var channelDataList = await channelProvider.SearchChannelByIdAsync(channelIds, cancelTask).ConfigureAwait(false);
                        foreach (var videoItem in result.Items)
                        {
                            var dataItem = new Onetube.Models.SearchVideo.Item();
                            dataItem.etag = videoItem.Etag;
                            dataItem.id = new Onetube.Models.SearchVideo.Id { videoId = videoItem.Id, kind = string.Empty };
                            dataItem.kind = videoItem.Kind;
                            var snippet = new Onetube.Models.SearchVideo.Snippet();
                            snippet.channelId = videoItem.Snippet.ChannelId;
                            snippet.channelTitle = videoItem.Snippet.ChannelTitle;
                            snippet.description = videoItem.Snippet.Description;
                            snippet.liveBroadcastContent = videoItem.Snippet.LiveBroadcastContent;
                            snippet.publishedAt = videoItem.Snippet.PublishedAt;
                            snippet.title = videoItem.Snippet.Title;
                            snippet.thumbnails = new Onetube.Models.SearchVideo.Thumbnails
                            {
                                @default = new Onetube.Models.SearchVideo.Default { url = videoItem.Snippet.Thumbnails.@Default.Url },
                                high = new Onetube.Models.SearchVideo.High { url = videoItem.Snippet.Thumbnails.High.Url },
                                medium = new Onetube.Models.SearchVideo.Medium { url = videoItem.Snippet.Thumbnails.Medium.Url }
                            };
                            var contentDetails = new Onetube.Models.SearchVideo.ContentDetails();

                            contentDetails.caption = videoItem.ContentDetails.Caption;
                            contentDetails.definition = videoItem.ContentDetails.Definition;
                            contentDetails.dimension = videoItem.ContentDetails.Dimension;
                            contentDetails.duration = videoItem.ContentDetails.Duration;
                            contentDetails.licensedContent = videoItem.ContentDetails.LicensedContent;

                            snippet.contentDetails = contentDetails;

                            var statistics = new Onetube.Models.SearchVideo.Statistics();
                            statistics.commentCount = videoItem.Statistics.CommentCount;
                            statistics.dislikeCount = videoItem.Statistics.DislikeCount;
                            statistics.favoriteCount = videoItem.Statistics.FavoriteCount;
                            statistics.likeCount = videoItem.Statistics.LikeCount;
                            statistics.viewCount = videoItem.Statistics.ViewCount;

                            snippet.statistics = statistics;
                            dataItem.snippet = snippet;

                            if (channelDataList != null)
                            {
                                if (channelDataList.Items.Any())
                                {
                                    var correspondChannel = channelDataList.Items.FirstOrDefault(x => x.Id.Equals(videoItem.Snippet.ChannelId));
                                    if (correspondChannel != null)
                                    {
                                        dataItem.snippet.channelDetails = new ChannelSnippet();
                                        dataItem.snippet.channelDetails.Description = correspondChannel.Snippet.Description;
                                        dataItem.snippet.channelDetails.PublishedAt = correspondChannel.Snippet.PublishedAt;
                                        dataItem.snippet.channelDetails.Thumbnails = new Models.SearchVideo.Thumbnails
                                        {
                                            @default = new Models.SearchVideo.Default
                                            {
                                                url = correspondChannel.Snippet.Thumbnails.Default.Url
                                            },
                                            high = new Models.SearchVideo.High
                                            {
                                                url = correspondChannel.Snippet.Thumbnails.High.Url
                                            },
                                            medium = new Models.SearchVideo.Medium
                                            {
                                                url = correspondChannel.Snippet.Thumbnails.Medium.Url
                                            }
                                        };
                                        dataItem.snippet.channelDetails.Title = correspondChannel.Snippet.Title;
                                    }
                                }
                            }

                            videoResult.items.Add(dataItem);
                        }
                        channelDataList = null;
                         
                        channelIds = null;
                    }
                }
                result = null;
            }
            return videoResult;
        }

        private async Task<Entities.MostViewedQuery.MostViewedQueryResult> ResolveMostReviewedRequest(StringBuilder petitionUri, TaskCompletionSource<Entities.MostViewedQuery.MostViewedQueryResult> taskCompletitionSource, CancellationTokenSource cancelTask)
        {
            if (cancelTask == null)
            {
                cancelTask = new CancellationTokenSource();
            }
           
            using (HttpClient client = new HttpClient())
            {
                HttpResponseMessage response = await client.GetAsync(petitionUri.ToString(), cancelTask.Token).ConfigureAwait(false);
                
                string resultJson;
                using (StreamReader reader = new StreamReader(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), Encoding.UTF8))
                {
                    try
                    {
                        resultJson = await reader.ReadToEndAsync().ConfigureAwait(false);

                        if (!string.IsNullOrEmpty(resultJson))
                        {
                            var entries = JsonConvert.DeserializeObject<MostViewedQueryResult>(resultJson);

                            taskCompletitionSource.SetResult(entries);
                            resultJson = null;
                            entries = null;
                        }
                        else
                        {
                            taskCompletitionSource.SetResult(null);
                        }
                        response.Dispose();
                       
                    }
                    catch (Exception ex)
                    {
                        taskCompletitionSource.SetException(ex);
                    }
                }
            }
            return await taskCompletitionSource.Task;
        }

        private async Task<VideoQueryResult> ResolveRequest(StringBuilder petitionUri, TaskCompletionSource<VideoQueryResult> taskCompletitionSource, CancellationTokenSource cancelTask)
        {
            if (cancelTask == null)
            {
                cancelTask = new CancellationTokenSource();
            }
           
            using (HttpClient client = new HttpClient())
            {
                HttpResponseMessage response = await client.GetAsync(petitionUri.ToString(), cancelTask.Token).ConfigureAwait(false);
                
                string resultJson;
                using (StreamReader reader = new StreamReader(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), Encoding.UTF8))
                {
                    try
                    {
                        resultJson = await reader.ReadToEndAsync().ConfigureAwait(false);

                        if (!string.IsNullOrEmpty(resultJson))
                        {
                            var entries = JsonConvert.DeserializeObject<VideoQueryResult>(resultJson);

                            taskCompletitionSource.SetResult(entries);
                            resultJson = null;
                            entries = null;
                        }
                        else
                        {
                            taskCompletitionSource.SetResult(null);
                        }
                        response.Dispose();
                    }
                    catch (Exception ex)
                    {
                        taskCompletitionSource.SetException(ex);
                    }
                }
            }
            return await taskCompletitionSource.Task.ConfigureAwait(false);
        }

        private async Task<SearchQueryResult> ResolveRequest(StringBuilder petitionUri, TaskCompletionSource<SearchQueryResult> taskCompletitionSource, CancellationTokenSource cancelTask)
        {
            if (cancelTask == null)
            {
                cancelTask = new CancellationTokenSource();
            }
           
            using (HttpClient client = new HttpClient())
            {
                HttpResponseMessage response = await client.GetAsync(petitionUri.ToString(), cancelTask.Token).ConfigureAwait(false);
                
                string resultJson;
                using (StreamReader reader = new StreamReader(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), Encoding.UTF8))
                {
                    try
                    {
                        resultJson = await reader.ReadToEndAsync().ConfigureAwait(false);

                        if (!string.IsNullOrEmpty(resultJson))
                        {
                            var entries = JsonConvert.DeserializeObject<SearchQueryResult>(resultJson);

                            taskCompletitionSource.SetResult(entries);
                            resultJson = null;
                            entries = null;
                        }
                        else
                        {
                            taskCompletitionSource.SetResult(null);
                        }
                        response.Dispose();
                    }
                    catch (Exception ex)
                    {
                        taskCompletitionSource.SetException(ex);
                    }
                }
            }
            return await taskCompletitionSource.Task;
        }

        public async Task<SearchVideoResult> GetRelatedVideosByVideoIdAsync(string videoId, string regionCode, string maxResults, CancellationTokenSource cancelTask)
        {
            StringBuilder petitionUri = new StringBuilder("https://www.googleapis.com/youtube/v3/search?");
         
            petitionUri.AppendFormat("part={0}", "snippet");
            petitionUri.AppendFormat("&relatedToVideoId={0}", videoId);
            petitionUri.AppendFormat("&regionCode={0}", regionCode);
            petitionUri.AppendFormat("&type={0}", "video");
            petitionUri.AppendFormat("&key={0}", AppKeys.API_KEY);

            var taskCompletitionSource = new TaskCompletionSource<SearchQueryResult>();
            var videoResult = new Models.SearchVideo.SearchVideoResult();
            videoResult.items = new List<Models.SearchVideo.Item>();
            var result = await ResolveRequest(petitionUri, taskCompletitionSource, cancelTask).ConfigureAwait(false);
            if (result != null)
            {
                videoResult.etag = result.etag;
                videoResult.kind = result.kind;
                videoResult.nextPageToken = result.nextPageToken;
                videoResult.pageInfo = new Models.SearchVideo.PageInfo { resultsPerPage = result.pageInfo.resultsPerPage, totalResults = result.pageInfo.totalResults };
                videoResult.prevPageToken = result.prevPageToken;
                videoResult.items = new List<Models.SearchVideo.Item>();
                if (result.items != null)
                {
                    if (result.items.Any())
                    {
                        videoProvider = new YoutubeVideoProvider();
                        channelProvider = new YoutubeChannelProvider();
                        string videoIds = string.Empty;
                        string channelIds = string.Empty;
                        int count = 0;
                        for (int i = 0; i <= result.items.Count - 1; i++)
                        {
                            count++;
                            var item = result.items.ElementAt(i);
                            if (item.id != null)
                            {
                                if (count >= result.items.Count)
                                {
                                    videoIds += item.id.videoId;
                                    channelIds += item.snippet.channelId;
                                }
                                else
                                {
                                    videoIds += item.id.videoId + ",";
                                    channelIds += item.snippet.channelId + ",";
                                }
                            }
                        }

                        var videoDataList = await videoProvider.GeVideoInfoAsync(videoIds, "MX", cancelTask).ConfigureAwait(false);
                        var channelDataList = await channelProvider.SearchChannelByIdAsync(channelIds, cancelTask).ConfigureAwait(false);
                        if (videoDataList != null)
                        {
                            foreach (var videoItem in result.items)
                            {
                                var dataItem = new Onetube.Models.SearchVideo.Item();

                                dataItem.etag = videoResult.etag;
                                dataItem.id = new Onetube.Models.SearchVideo.Id { kind = videoItem.id.kind, videoId = videoItem.id.videoId };
                                dataItem.kind = videoItem.kind;
                                var snippet = new Onetube.Models.SearchVideo.Snippet();
                                snippet.channelId = videoItem.snippet.channelId;
                                snippet.channelTitle = videoItem.snippet.channelTitle;
                                snippet.description = videoItem.snippet.description;
                                snippet.liveBroadcastContent = videoItem.snippet.liveBroadcastContent;
                                snippet.publishedAt = videoItem.snippet.publishedAt;
                                snippet.title = videoItem.snippet.title;
                                snippet.thumbnails = new Onetube.Models.SearchVideo.Thumbnails
                                {
                                    @default = new Onetube.Models.SearchVideo.Default { url = videoItem.snippet.thumbnails.@default.url },
                                    high = new Onetube.Models.SearchVideo.High { url = videoItem.snippet.thumbnails.high.url },
                                    medium = new Onetube.Models.SearchVideo.Medium { url = videoItem.snippet.thumbnails.medium.url }
                                };
                                var contentDetails = new Onetube.Models.SearchVideo.ContentDetails();
                                var correspondVideo = videoDataList.Items.FirstOrDefault(x => x.Id.Equals(videoItem.id.videoId));
                                if (correspondVideo != null)
                                {
                                    contentDetails.caption = correspondVideo.ContentDetails.Caption;
                                    contentDetails.definition = correspondVideo.ContentDetails.Definition;
                                    contentDetails.dimension = correspondVideo.ContentDetails.Dimension;
                                    contentDetails.duration = correspondVideo.ContentDetails.Duration;
                                    contentDetails.licensedContent = correspondVideo.ContentDetails.LicensedContent;
                                }

                                snippet.contentDetails = contentDetails;

                                var statistics = new Onetube.Models.SearchVideo.Statistics();
                                statistics.commentCount = correspondVideo.Statistics.CommentCount;
                                statistics.dislikeCount = correspondVideo.Statistics.DislikeCount;
                                statistics.favoriteCount = correspondVideo.Statistics.FavoriteCount;
                                statistics.likeCount = correspondVideo.Statistics.LikeCount;
                                statistics.viewCount = correspondVideo.Statistics.ViewCount;

                                snippet.statistics = statistics;
                                dataItem.snippet = snippet;
                                if (channelDataList != null && channelDataList.Items!=null)
                                {
                                    if (channelDataList.Items.Any())
                                    {
                                        var correspondChannel = channelDataList.Items.FirstOrDefault(x => x.Id.Equals(videoItem.snippet.channelId));
                                        if (correspondChannel != null)
                                        {
                                            dataItem.snippet.channelDetails = new ChannelSnippet();
                                            dataItem.snippet.channelDetails.Description = correspondChannel.Snippet.Description;
                                            dataItem.snippet.channelDetails.PublishedAt = correspondChannel.Snippet.PublishedAt;
                                            dataItem.snippet.channelDetails.Thumbnails = new Models.SearchVideo.Thumbnails
                                            {
                                                @default = new Models.SearchVideo.Default
                                                {
                                                    url = correspondChannel.Snippet.Thumbnails.Default.Url
                                                },
                                                high = new Models.SearchVideo.High
                                                {
                                                    url = correspondChannel.Snippet.Thumbnails.High.Url
                                                },
                                                medium = new Models.SearchVideo.Medium
                                                {
                                                    url = correspondChannel.Snippet.Thumbnails.Medium.Url
                                                }
                                            };
                                            dataItem.snippet.channelDetails.Title = correspondChannel.Snippet.Title;
                                        }
                                    }
                                }
                                videoResult.items.Add(dataItem);
                            }
                            videoDataList = null;
                            channelDataList = null;
                            videoIds = null;
                            channelIds = null;
                        }
                    }
                }
                result = null;
            }

            return videoResult;
        }

        public async Task<SearchVideoResult> GetRelatedVideosByVideoIdNextPageAsync(string videoId, string regionCode, string maxResults, string nextPageToken, CancellationTokenSource cancelTask)
        {
            StringBuilder petitionUri = new StringBuilder("https://www.googleapis.com/youtube/v3/search?");
         
            petitionUri.AppendFormat("part={0}", "snippet");
            petitionUri.AppendFormat("&relatedToVideoId={0}", videoId);
            petitionUri.AppendFormat("&regionCode={0}", regionCode);
            petitionUri.AppendFormat("&pageToken={0}", nextPageToken);
            petitionUri.AppendFormat("&type={0}", "video");
            petitionUri.AppendFormat("&key={0}", AppKeys.API_KEY);

            var taskCompletitionSource = new TaskCompletionSource<SearchQueryResult>();
            var videoResult = new Models.SearchVideo.SearchVideoResult();
            videoResult.items = new List<Models.SearchVideo.Item>();
            var result = await ResolveRequest(petitionUri, taskCompletitionSource, cancelTask).ConfigureAwait(false);
            if (result != null)
            {
                videoResult.etag = result.etag;
                videoResult.kind = result.kind;
                videoResult.nextPageToken = result.nextPageToken;
                videoResult.pageInfo = new Models.SearchVideo.PageInfo { resultsPerPage = result.pageInfo.resultsPerPage, totalResults = result.pageInfo.totalResults };
                videoResult.prevPageToken = result.prevPageToken;
                videoResult.items = new List<Models.SearchVideo.Item>();
                if (result.items != null)
                {
                    if (result.items.Any())
                    {
                        videoProvider = new YoutubeVideoProvider();
                        channelProvider = new YoutubeChannelProvider();
                        string videoIds = string.Empty;
                        string channelIds = string.Empty;
                        int count = 0;
                        for (int i = 0; i <= result.items.Count - 1; i++)
                        {
                            count++;
                            var item = result.items.ElementAt(i);
                            if (item.id != null)
                            {
                                if (count >= result.items.Count)
                                {
                                    videoIds += item.id.videoId;
                                    channelIds += item.snippet.channelId;
                                }
                                else
                                {
                                    videoIds += item.id.videoId + ",";
                                    channelIds += item.snippet.channelId + ",";
                                }
                            }
                        }

                        var videoDataList = await videoProvider.GeVideoInfoAsync(videoIds, "MX", cancelTask).ConfigureAwait(false);
                        var channelDataList = await channelProvider.SearchChannelByIdAsync(channelIds, cancelTask).ConfigureAwait(false);
                        if (videoDataList != null)
                        {
                            foreach (var videoItem in result.items)
                            {
                                var dataItem = new Onetube.Models.SearchVideo.Item();

                                dataItem.etag = videoResult.etag;
                                dataItem.id = new Onetube.Models.SearchVideo.Id { kind = videoItem.id.kind, videoId = videoItem.id.videoId };
                                dataItem.kind = videoItem.kind;
                                var snippet = new Onetube.Models.SearchVideo.Snippet();
                                snippet.channelId = videoItem.snippet.channelId;
                                snippet.channelTitle = videoItem.snippet.channelTitle;
                                snippet.description = videoItem.snippet.description;
                                snippet.liveBroadcastContent = videoItem.snippet.liveBroadcastContent;
                                snippet.publishedAt = videoItem.snippet.publishedAt;
                                snippet.title = videoItem.snippet.title;
                                snippet.thumbnails = new Onetube.Models.SearchVideo.Thumbnails
                                {
                                    @default = new Onetube.Models.SearchVideo.Default { url = videoItem.snippet.thumbnails.@default.url },
                                    high = new Onetube.Models.SearchVideo.High { url = videoItem.snippet.thumbnails.high.url },
                                    medium = new Onetube.Models.SearchVideo.Medium { url = videoItem.snippet.thumbnails.medium.url }
                                };
                                var contentDetails = new Onetube.Models.SearchVideo.ContentDetails();
                                var correspondVideo = videoDataList.Items.FirstOrDefault(x => x.Id.Equals(videoItem.id.videoId));
                                if (correspondVideo != null)
                                {
                                    contentDetails.caption = correspondVideo.ContentDetails.Caption;
                                    contentDetails.definition = correspondVideo.ContentDetails.Definition;
                                    contentDetails.dimension = correspondVideo.ContentDetails.Dimension;
                                    contentDetails.duration = correspondVideo.ContentDetails.Duration;
                                    contentDetails.licensedContent = correspondVideo.ContentDetails.LicensedContent;
                                }

                                snippet.contentDetails = contentDetails;

                                var statistics = new Onetube.Models.SearchVideo.Statistics();
                                statistics.commentCount = correspondVideo.Statistics.CommentCount;
                                statistics.dislikeCount = correspondVideo.Statistics.DislikeCount;
                                statistics.favoriteCount = correspondVideo.Statistics.FavoriteCount;
                                statistics.likeCount = correspondVideo.Statistics.LikeCount;
                                statistics.viewCount = correspondVideo.Statistics.ViewCount;

                                snippet.statistics = statistics;
                                dataItem.snippet = snippet;
                                if (channelDataList != null)
                                {
                                    if (channelDataList.Items!=null && channelDataList.Items.Any())
                                    {
                                        var correspondChannel = channelDataList.Items.FirstOrDefault(x => x.Id.Equals(videoItem.snippet.channelId));
                                        if (correspondChannel != null)
                                        {
                                            dataItem.snippet.channelDetails = new ChannelSnippet();
                                            dataItem.snippet.channelDetails.Description = correspondChannel.Snippet.Description;
                                            dataItem.snippet.channelDetails.PublishedAt = correspondChannel.Snippet.PublishedAt;
                                            dataItem.snippet.channelDetails.Thumbnails = new Models.SearchVideo.Thumbnails
                                            {
                                                @default = new Models.SearchVideo.Default
                                                {
                                                    url = correspondChannel.Snippet.Thumbnails.Default.Url
                                                },
                                                high = new Models.SearchVideo.High
                                                {
                                                    url = correspondChannel.Snippet.Thumbnails.High.Url
                                                },
                                                medium = new Models.SearchVideo.Medium
                                                {
                                                    url = correspondChannel.Snippet.Thumbnails.Medium.Url
                                                }
                                            };
                                            dataItem.snippet.channelDetails.Title = correspondChannel.Snippet.Title;
                                        }
                                    }
                                }
                                videoResult.items.Add(dataItem);
                            }
                            videoDataList = null;
                            channelDataList = null;
                            videoIds = null;
                            channelIds = null;
                        }
                    }
                }
                result = null;
            }

            return videoResult;
        }

        private string getFormattedVideoId(string str)
        {
            string result = string.Empty;
            for (int i = str.Length - 1; i >= 0; i--)
            {
                if (str[i] == ':')
                    break;
                result = str[i].ToString() + result;
            }

            return result;
        }
    }
}